﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using warcaby.Backpropagation;
using warcaby.LearningRateFunctions;
using warcaby.Initializers;
using warcaby.Properties;
using warcaby.SOM;
namespace warcaby
{

    class LayeredLearning
    {
        int MinMaxwithoutAlphaBeta=0;
        int MinMaxwithAlphaBeta=0;
        int result = 0;
        public BackpropagationNetwork network;
        public LayeredLearning()
        {
            LinearLayer inputLayer = new LinearLayer(34);
            
            SigmoidLayer hiddenLayer = new SigmoidLayer(8);
            SigmoidLayer outputLayer = new SigmoidLayer(1);
            new BackpropagationConnector(inputLayer, hiddenLayer);
            new BackpropagationConnector(hiddenLayer, outputLayer);
            network = new BackpropagationNetwork(inputLayer, outputLayer);


        }
        public void Training(int leveloftraining1to100)
        {
            TrainingSet trainingSet = new TrainingSet(34, 1);
            double[] set;
            int k = 0;
            Map map;
            int result = 0;
            while (k != 12)
            { 
                k++;
                for (int i = 0; i < leveloftraining1to100 * 4; i++)
                {
                    Stack<Map> stmap = trainingstack(k, 4);
                    {
                        while (stmap.Count != 0)
                        {
                            map = stmap.Pop();
                            set = map.getArray();
                            trainingSet.Add(new TrainingSample(set, new double[1] { result }));
                            network.Learn(trainingSet, 10);
                            trainingSet.Clear();
                        }
                    }
                }
                Console.WriteLine(k);

            }
        }
        //color can be only "black" or "white". 
        public Stack<Move> MinMax(Map map, Stack<Move> Moves,int depth)
        {
            Stack<Move> bestmove=new Stack<Move>();
            Move move;
            Map maptmp;
            string color=map.Turn;
            float bestvalue = 0;
            if(color=="black")
                bestvalue = -2;
            if (color == "white")
                bestvalue = 2;


            while (Moves.Count != 0)
            {
                move = Moves.Pop();
                maptmp=map.CopyMap(map);
                if (maptmp.Move(move) == -1)
                    Console.WriteLine("error");//debug
                float value = MinMaxRecursion(maptmp, depth, map.GetBlack()+map.GetBlackQueen()-map.GetWhite()-map.GetWhiteQueen());


                if (color == "black"&&value>bestvalue)
                {
                    bestvalue = value;
                    bestmove.Clear();
                }
                if (color == "white" && value < bestvalue)
                {
                    bestvalue = value;
                    bestmove.Clear();
                }
                if (value == bestvalue)
                    bestmove.Push(move);
           


            }
            //used only to test:
       //     Console.WriteLine("Without AlphaBeta: "+MinMaxwithoutAlphaBeta+". value:"+bestvalue);
            


            return bestmove;
        }
        public Stack<Move> MinMaxAB(Map map, Stack<Move> Moves, int depth)
        {
            Stack<Move> bestmove = new Stack<Move>();
            Move move;
            Map maptmp;
            string color = map.Turn;
            float bestvalue = 0;
            if (color == "black")
                bestvalue = -2;
            if (color == "white")
                bestvalue = 2;


            while (Moves.Count != 0)
            {
                move = Moves.Pop();
                maptmp = map.CopyMap(map);
                if (maptmp.Move(move) == -1)
                    Console.WriteLine("error");//debug
                float value = MinMaxAlphaBetaRecursion(maptmp, depth, map.GetBlack() + map.GetBlackQueen() - map.GetWhite() - map.GetWhiteQueen(), -2, 2);


                if (color == "black" && value > bestvalue)
                {
                    bestvalue = value;
                    bestmove.Clear();
                }
                if (color == "white" && value < bestvalue)
                {
                    bestvalue = value;
                    bestmove.Clear();
                }
                if (value == bestvalue)
                    bestmove.Push(move);



            }
            //used only to test:
       //     Console.WriteLine("Without AlphaBeta: " + MinMaxwithAlphaBeta + ". value:" + bestvalue);



            return bestmove;
        }
        private float MinMaxRecursion(Map map, int depth, int startdiff)
        {
            Map maptmp;
            string color = map.Turn;
            int amount;
            float bestvalue = 0;
            if (color == "black")
                bestvalue = -2;
            if (color == "white")
                bestvalue = 2;

            //one line to delete. test purpose
            MinMaxwithoutAlphaBeta++;
            depth--;

            if(depth==0)
            {
                int bl = map.GetBlack();
                int gw = map.GetWhite();
                int bq = map.GetBlackQueen();
                int wq = map.GetWhiteQueen();
                amount=bl+bq-gw-wq;
           
                if(amount==startdiff)
                    return 0;
                if(amount>startdiff)
                    return (float)1/2;
                if(amount<startdiff)
                    return (float)-1/2;

            }


            
            Stack<Move> Moves = map.GetAllMoves();
            if(Moves.Count==0)
            {
                if(color=="white")
                    return 1;
                if(color=="black")
                    return -1;
            }
            while (Moves.Count != 0)
            {
                maptmp = map.CopyMap(map);
                maptmp.Move(Moves.Pop());
                float value = MinMaxRecursion(maptmp, depth,startdiff);
                if (color == "black" && value > bestvalue)
                    bestvalue = value;
                if (color == "white" && value < bestvalue)
                    bestvalue = value;  
            }


            return bestvalue;
        }

        private float MinMaxAlphaBetaRecursion(Map map, int depth, int startdiff,float blackbest, float whitebest)
        {


            Map maptmp;
            string color = map.Turn;
            int amount;
            float bestvalue = 0;
            if (color == "black")
                bestvalue = -2;
            if (color == "white")
                bestvalue = 2;

            //one line to delete. test purpose
            MinMaxwithAlphaBeta++;
            depth--;

            if (depth == 0)
            {
                int bl = map.GetBlack();
                int gw = map.GetWhite();
                int bq = map.GetBlackQueen();
                int wq = map.GetWhiteQueen();
                amount = bl + bq - gw - wq;
                if (amount == startdiff)
                    return 0;
                if (amount > startdiff)
                    return (float)1 / 2;
                if (amount < startdiff)
                    return (float)-1 / 2;

            }



            Stack<Move> Moves = map.GetAllMoves();
            if (Moves.Count == 0)
            {
                if (color == "white")
                    return 1;
                if (color == "black")
                    return -1;
            }
            while (Moves.Count != 0)
            {

                maptmp = map.CopyMap(map);
                maptmp.Move(Moves.Pop());
                float value = MinMaxAlphaBetaRecursion(maptmp, depth, startdiff, blackbest, whitebest);
                if (color == "black" && value > bestvalue)
                {
                    bestvalue = value;
                    blackbest = value;
                }
                if (color == "white" && value < bestvalue)
                {
                    bestvalue = value;
                    whitebest = value;
                }
                if (whitebest <= blackbest)
                     break;
                
                
            }


            return bestvalue;
        }

        private Stack<Map> trainingstack(int nrofenem, int level)
        {
            Stack<Move> Moves = new Stack<Move>();
            Stack<Move> stackbest = new Stack<Move>();
            Move best = new Move();
            int count;
            Random rand = new Random();
            int happybest;
            Map map=new Map();
            Stack<Map> stmap = new Stack<Map>(); 
            while (true)
            {

                Moves = map.GetAllMoves();
                count = Moves.Count;
                if (map.Withoutslaughter >= 20)
                {
                    result = 0;
                    return stmap;
                }
                if (map.Turn == "black" && count == 0)
                {
                    result = 1;
                    return stmap;
                }
                if (map.Turn == "white" && count == 0)
                {
                    result = -1;
                    return stmap;
                }
                count = Moves.Count;

                if (map.Turn == "white")
                    stackbest = MinMaxAB(map, Moves, level);
                if (map.Turn == "black")
                {
                    stackbest = MinMaxAB(map, Moves, level - 1);
                    int black=map.GetBlack();
               //     if(nrofenem==black)
                        stmap.Push(map);
                    //if (nrofenem > black)
                    //    return stmap;
                }
                happybest = rand.Next() % stackbest.Count;
                best = stackbest.ToArray()[happybest];
                map.Move(best);
            
            }

        }
        public Stack<Move> LLmove(Map map, Stack<Move> Moves)
        {
            double bestvalue = -1111;
            Move M1 = new Move();
            int count = Moves.Count;
            Stack<Move> m= new Stack<Move>();
            while (Moves.Count != 0)
            {

                M1 = Moves.Pop();
                Map maptmp = map.CopyMap(map);
                if (maptmp.Move(M1) == -1)
                    Console.WriteLine("error");//debug
                double[] val1 = network.Run(maptmp.getArray());
                double val = val1[0];
                if (bestvalue == val)
                {
                    m.Push(M1);
                }
                if (map.Turn == "black")
                    if (bestvalue < val || bestvalue == -1111)
                    {
                        m.Clear();
                        m.Push(M1);
                        bestvalue = val;
                    }
                if (map.Turn == "white")
                    if (bestvalue > val || bestvalue == -1111)
                    {
                        m.Clear();
                        m.Push(M1);
                        bestvalue = val;
                    }


            }
            return m;
        }
    }
 
}
